package kassiopeia.agent.alerting;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.activation.DataSource;
import javax.mail.MessagingException;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.TimerTask;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class AlertingTimer extends TimerTask {

    private final Logger logger = Logger.getLogger(AlertingTimer.class);
    @Autowired
    private AlertSender alertSender;
    @Autowired
    private NodeName nodeName;
    private int maxBulkSize = 50;

    public void setBulkSize(int bulkSize) {
        this.maxBulkSize = bulkSize;
    }
    private volatile List<Alert> alertsInBuffer = new ArrayList<Alert>();
    private volatile List<Alert> pluginAlertsBuffer = new ArrayList<Alert>();
    private volatile int number;
    private List<String> emailList;
    private List<String> emailListPlugin;
    private String version;

    @Override
    public void run() {
        if (alertSender.isEnabled()) {
            sendAlerts();
            sendPluginAlerts();
        }
    }

    @Value("${mail.list}")
    public void setEmailList(String emailList) {
        this.emailList = new LinkedList<String>();
        for (String mail : emailList.split(";")) {
            this.emailList.add(mail.trim());
        }
    }

    @Value("${mail.list.plugin}")
    public void setEmailListPlugin(String emailListPlugin) {
        this.emailListPlugin = new LinkedList<String>();
        for (String mail : emailListPlugin.split(";")) {
            this.emailListPlugin.add(mail.trim());
        }
    }

    @Value("${kassiopeia.version}")
    public void setVersion(String version) {
        this.version = version;
    }

    private String getVersion() {
        return this.version;
    }

    private boolean sendAlerts() {

        List<Alert> alertsToSend = this.alertsInBuffer;
        int n = this.number;
        if (alertsToSend.isEmpty()) {
            return true;
        }

        this.alertsInBuffer = new ArrayList<Alert>(this.maxBulkSize);
        this.number = 0;

        send(alertsToSend, n);
        return true;
    }

    private boolean sendPluginAlerts() {
        List<Alert> alertsToSend = this.pluginAlertsBuffer;
        int n = alertsToSend.size();
        if (alertsToSend.isEmpty()) {
            return true;
        }

        this.pluginAlertsBuffer = new ArrayList<Alert>();
        send(alertsToSend, n);
        
        return true;
    }

    private void send(List<Alert> alertsToSend, int n) {
        List<String> sendTo = emailListPlugin;
        if (sendTo.isEmpty()) {
            logger.warn("No recipients for alerting");
        }

        String subject = toSubject(alertsToSend);
        boolean hi = toPriority(alertsToSend);
        try {
            String content = getContent(alertsToSend, n);
            alertSender.send(subject, sendTo, content, hi, toAttachements(alertsToSend));
            logger.info("ALERT email sent: " + subject);
        } catch (MessagingException ex) {
            logger.error("Cannot send alerts", ex);
        }
    }

    private String toSubject(List<Alert> alertsToSend) {
        if (alertsToSend.size() == 1) {
            return "[ALERT] " + alertsToSend.get(0).getSubject();
        } else {
            return "[ALERT] Multiple (" + alertsToSend.size() + ") alerts from Kassiopeia";
        }
    }

    private boolean toPriority(List<Alert> alertsToSend) {
        for (Alert mal : alertsToSend) {
            if (mal.isHi()) {
                return true;
            }
        }
        return false;
    }

    private DataSource[] toAttachements(List<Alert> alertsToSend) {
        List<DataSource> all = new ArrayList<DataSource>();
        int i = 1;
        for (Alert a : alertsToSend) {
            for (DataSource att : a.getAttachments("Alert#" + i + "_Attachment")) {
                all.add(att);
            }
            i++;
        }
        return all.toArray(new DataSource[all.size()]);
    }

    private String getContent(List<Alert> alertsToSend, int n) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < alertsToSend.size(); i++) {
            Alert a = alertsToSend.get(i);
            sb.append("Alert#").append(i + 1).append(" from thread ").append(a.getThreadName()).append("\n");
            sb.append("Subject: ").append(a.getSubject()).append("\n");
            sb.append(a.getContent()).append("\n\n--------------------------------\n");
        }
        sb.append("Alert sent from ").append(nodeName.getNodeName()).append("::").append(getVersion()).append("\n");
        int skipped = n - alertsToSend.size();
        if (skipped > 0) {
            sb.append(skipped).append(" other alerts skipped");
        }
        return sb.toString();
    }

    void alert(Alert alert) {
        List<Alert> list;
        if (alert.getType().equals(AlertType.PLUGIN_ALERT)) {
            list = this.pluginAlertsBuffer;
            list.add(alert);
        } else {
            list = this.alertsInBuffer;
            if (list.size() < this.maxBulkSize) {
                list.add(alert);
            }
            this.number++;
        }
    }
}
